/*
 * @author 渡一
 * @date 2024-12-03 21:06:24
 * @description 用于pinia持久化插件
 * @see 🚀 https://www.bilibili.com/video/BV1KT421D7Xk/?spm_id_from=333.337.search-card.all.click&vd_source=9efadbd9bd76b9c14f9589f260a0c1ac
 * @status done
 */

import Storage from '@/utils/storage'
import type { PiniaPluginContext } from 'pinia'

const KEY_PREFIX = 'PINIA_STORE_'
const storageInstance = singleton(Storage)
const storage = new storageInstance(KEY_PREFIX, localStorage)

/**
 * 用于pinia持久化插件
 * @param context 上下文
 */
export function usePersistPlugin(context: PiniaPluginContext) {
  // 获取上下文中的store
  const { store } = context
  // 打印store的id和上下文
  //   console.log(storage)

  // 监听窗口关闭事件，将store的状态保存到本地存储中
  window.addEventListener('beforeunload', () => {
    storage.set(store.$id, JSON.stringify(store.$state))
  })

  // 尝试从本地存储中获取数据，并更新store的状态
  try {
    const localData = storage.get(store.$id)
    if (localData) {
      store.$patch(JSON.parse(localData))
    }
  } catch (e) {
    // 如果数据持久化失败，抛出错误
    throw new Error('数据持久化失败')
  }
}

type Constructor<T> = new (...args: any[]) => T

/**
 * 导出一个函数，用于创建单例模式
 * @param className 类
 * @returns
 */
export function singleton<T>(className: Constructor<T>) {
  // 定义一个变量，用于存储实例
  let instance: any
  // 返回一个代理对象
  return new Proxy(className, {
    // 当使用new关键字创建实例时，执行该函数
    construct(target, args) {
      // 定义一个代理类
      class ProxyClass {
        constructor() {
          // 如果实例为空，则创建一个新的实例
          if (instance == null) {
            instance = new target(...args)
          }
          // 返回实例
          return instance
        }
      }
      // 返回代理类的实例
      return new ProxyClass()
    }
  })
}
